package com.ztstkj.lzservices.serialports

import com.ztstkj.lzservices.exceptions.LogConstant
import com.ztstkj.lzservices.extension.ByteArrayExtension.crc16
import com.ztstkj.lzservices.extension.ByteArrayExtension.crc16Verify
import com.ztstkj.lzservices.extension.ByteArrayExtension.lowToHigh
import com.ztstkj.lzservices.extension.ByteArrayExtension.sub
import com.ztstkj.lzservices.extension.ByteArrayExtension.toHexStr
import com.ztstkj.lzservices.extension.ByteArrayExtension.toInt
import com.ztstkj.lzservices.extension.ByteArrayExtension.toLong2
import com.ztstkj.lzservices.extension.ExceptionExt.toStackTraceString
import com.ztstkj.lzservices.extension.IntExtension.toHex1X
import com.ztstkj.lzservices.extension.IntExtension.toHex2X
import com.ztstkj.lzservices.extension.StringExtension.str2ByteArray
import com.ztstkj.lzservices.mmkvs.MmkvManager
import com.ztstkj.lzservices.utils.DateTimeUtil


class ModbusData() {
    constructor(orginByteArray: ByteArray) : this() {
        try {
            data = orginByteArray
            if (orginByteArray.isEmpty()) return
            dataHex = orginByteArray.toHexStr()
            isCrc16 = data.crc16Verify()
            if (!isCrc16) return

            slaveId = orginByteArray[0].toInt()
            if (slaveId != 1) return
            functionCode = orginByteArray[1].toInt()
            start = orginByteArray.sub(2, 2).toInt()
            dataLength = orginByteArray.sub(4, 2).toInt()
            dataByteSize = orginByteArray[6].toInt()
            if (functionCode == 3) {
                //获取时间
                if (start == 73) {
                    operate = ModbusOperate.Time  //刷卡和扫码
                    val dateField = DateTimeUtil.getNowDateField()
                    yearHex = dateField.year.toHex2X().str2ByteArray().toHexStr(" ")
                    monthHex = dateField.month.toHex1X().str2ByteArray().toHexStr(" ")
                    dayHex = dateField.day.toHex1X().str2ByteArray().toHexStr(" ")
                    hourHex = dateField.hour.toHex1X().str2ByteArray().toHexStr(" ")
                    minuteHex = dateField.minute.toHex1X().str2ByteArray().toHexStr(" ")
                    secondHex = dateField.second.toHex1X().str2ByteArray().toHexStr(" ")
                    dayOfWeekHex = dateField.dayOfweek.toHex1X().str2ByteArray().toHexStr(" ")
                    dayOfWeek=dateField.dayOfweek
                    dateTime=dateField.dateTime
                }
            } else if (functionCode == 16) {
                if (start == 10) {
                    operate = ModbusOperate.Card  //刷卡和扫码
                    if (dataByteSize != 4) throw RuntimeException("卡号字节数量不正确")
                    //0001 1170
                    // Little-Endian模式下    7011 0100
                    // Big-Endian模式  0001 1170
                    // 1170 0001 实际 张工的不是严格的这两种模式，我期望的是Big-Endian模式，张工的这个需要两个寄存器，低位和高位调换
                    val bytes = orginByteArray.copyOfRange(7, 7 + dataByteSize)
                    //DebugUtil.debugOut("======"+bytes.lowToHigh().toLong2().toString())
                    carNo = bytes.lowToHigh().toLong2()

                } else if (start == 6) {
                    operate = ModbusOperate.Rate
                    if (dataByteSize != 22) throw RuntimeException("称重字节数量不正确")
                    val bytes = orginByteArray.copyOfRange(7, 7 + dataByteSize)
                    dateTime = "${bytes.sub(0, 2).toInt()}年${bytes.sub(2).toInt()}月${
                        bytes.sub(3).toInt()
                    }日 ${bytes.sub(4).toInt()}:${bytes.sub(5).toInt()}:${
                        bytes.sub(6).toInt()
                    } 星期${bytes.sub(7).toInt()}"
                    carNo = bytes.sub(8, 4).lowToHigh().toLong2()
                    weight = bytes.sub(12, 4).lowToHigh().toInt()
                    rate = bytes.sub(16, 2).toInt()
                    categoryType = bytes.sub(18, 2).toInt()
                    category = bytes.sub(20, 2).toInt()

                } else if (start == 12) {
                    operate = ModbusOperate.Weight
                    val bytes = orginByteArray.copyOfRange(7, 7 + dataByteSize)
                    weight = bytes.sub(0, 4).lowToHigh().toInt()   //4个字节
                } else if (start == 16) {
                    operate = ModbusOperate.Category
                    val bytes = orginByteArray.copyOfRange(7, 7 + dataByteSize)
                    category = bytes.sub(0, 2).toInt() //两个字节
                }
            }

        } catch (e: Exception) {
            e.printStackTrace()
            MmkvManager.addLog(LogConstant.MODBUS,e.toStackTraceString())
        }

    }

    @Transient
    private lateinit var data: ByteArray
    var slaveId: Int = 0 //主机地址
    private var functionCode: Int = 0//功能码
    private var start: Int = 0  // 开始地址
    private var dataLength = 0 //寄存器数量
    private var dataByteSize = 0// 字节数量 几个字节
    private var isCrc16: Boolean = false
    var carNo: Long = 0L             // 卡号
    var weight: Int = 0           //重量
    var rate: Int = 0              //评价
    private var categoryType: Int = 0      //分类类型
    var category: Int = 0          //垃圾类别
    @Transient
    var dataHex: String = ""       //字节16进制
    var operate: ModbusOperate? = null
    private var yearHex: String = ""
    private var monthHex: String = ""
    private var dayHex: String = ""
    private var hourHex: String = ""
    private var secondHex: String = ""
    private var minuteHex: String = ""
    private var dayOfWeekHex: String = ""
    private var dateTime: String = ""
    private var dayOfWeek: Int=0
    fun crc16Verify(): Boolean {
        return data.crc16Verify()
    }

    fun successTime(): ByteArray {
        val resp = "${slaveId.toHex1X()}${functionCode.toHex1X()}${8.toHex1X()} $yearHex $monthHex $dayHex $hourHex $minuteHex $secondHex $dayOfWeekHex"
        return resp.str2ByteArray().crc16()
    }

    fun success(): ByteArray {
        val resp =
            "${slaveId.toHex1X()}${functionCode.toHex1X()}${start.toHex2X()}${dataLength.toHex2X()}"
        return resp.str2ByteArray().crc16()
    }

    fun error(error: ModbusError): ByteArray {
        val resp = "${slaveId.toHex1X()}${144.toHex1X()}${error.num.toHex1X()}"
        return resp.str2ByteArray().crc16()
    }

    override fun toString(): String {
        var result = " $operate =>"
        result += when (operate) {
            ModbusOperate.Card -> "card:$carNo"
            ModbusOperate.Weight -> "weight:$weight"
            ModbusOperate.Rate -> "card:$carNo category:$category rate:$rate weight:$weight"
            ModbusOperate.Category -> "category:$category"
            ModbusOperate.Time -> "date:$dateTime week:$dayOfWeek"
            null -> "未知"
        }
        return result
    }

}